diff options
Diffstat (limited to 'app/[lng]/engineering/(engineering)/pq_new/[vendorId]/[submissionId]/page.tsx')
| -rw-r--r-- | app/[lng]/engineering/(engineering)/pq_new/[vendorId]/[submissionId]/page.tsx | 215 |
1 files changed, 215 insertions, 0 deletions
diff --git a/app/[lng]/engineering/(engineering)/pq_new/[vendorId]/[submissionId]/page.tsx b/app/[lng]/engineering/(engineering)/pq_new/[vendorId]/[submissionId]/page.tsx new file mode 100644 index 00000000..28ce3128 --- /dev/null +++ b/app/[lng]/engineering/(engineering)/pq_new/[vendorId]/[submissionId]/page.tsx @@ -0,0 +1,215 @@ +import * as React from "react" +import { Metadata } from "next" +import Link from "next/link" +import { notFound } from "next/navigation" +import { ArrowLeft } from "lucide-react" +import { Shell } from "@/components/shell" +import { Button } from "@/components/ui/button" +import { Badge } from "@/components/ui/badge" +import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert" +import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs" +import { Separator } from "@/components/ui/separator" +import { getPQById, getPQDataByVendorId } from "@/lib/pq/service" +import { unstable_noStore as noStore } from 'next/cache' +import { PQReviewWrapper } from "@/components/pq-input/pq-review-wrapper" + +export const metadata: Metadata = { + title: "PQ 검토", + description: "협력업체의 Pre-Qualification 답변을 검토합니다.", +} + +// 페이지가 기본적으로 동적임을 나타냄 +export const dynamic = "force-dynamic" + +interface PQReviewPageProps { + params: Promise<{ + vendorId: string; + submissionId: string; + }> +} + +export default async function PQReviewPage(props: PQReviewPageProps) { + // 캐시 비활성화 + noStore() + + const params = await props.params + const vendorId = parseInt(params.vendorId, 10) + const submissionId = parseInt(params.submissionId, 10) + + try { + // PQ Submission 정보 조회 + const pqSubmission = await getPQById(submissionId, vendorId) + + // PQ 데이터 조회 (질문과 답변) + const pqData = await getPQDataByVendorId(vendorId, pqSubmission.projectId || undefined) + + // 프로젝트 정보 (프로젝트 PQ인 경우) + const projectInfo = pqSubmission.projectId ? { + id: pqSubmission.projectId, + projectCode: pqSubmission.projectCode || '', + projectName: pqSubmission.projectName || '', + status: pqSubmission.status, + submittedAt: pqSubmission.submittedAt, + } : null + + // PQ 유형 및 상태 레이블 + const typeLabel = pqSubmission.type === "GENERAL" ? "일반 PQ" : "프로젝트 PQ" + const statusLabel = getStatusLabel(pqSubmission.status) + const statusVariant = getStatusVariant(pqSubmission.status) + + // 수정 가능 여부 (SUBMITTED 상태일 때만 가능) + const canReview = pqSubmission.status === "SUBMITTED" + + return ( + <Shell className="gap-6 max-w-5xl"> + <div className="flex items-center justify-between"> + <div className="flex items-center gap-4"> + <Button variant="outline" size="sm" asChild> + <Link href="/evcp/pq_new"> + <ArrowLeft className="w-4 h-4 mr-2" /> + 목록으로 + </Link> + </Button> + <div> + <h2 className="text-2xl font-bold tracking-tight"> + {pqSubmission.vendorName} - {typeLabel} + </h2> + <div className="flex items-center gap-2 mt-1"> + <Badge variant={statusVariant}>{statusLabel}</Badge> + {projectInfo && ( + <span className="text-muted-foreground"> + {projectInfo.projectName} ({projectInfo.projectCode}) + </span> + )} + </div> + </div> + </div> + </div> + + {/* 상태별 알림 */} + {pqSubmission.status === "SUBMITTED" && ( + <Alert> + <AlertTitle>제출 완료</AlertTitle> + <AlertDescription> + 협력업체가 {formatDate(pqSubmission.submittedAt)}에 PQ를 제출했습니다. 검토 후 승인 또는 거부할 수 있습니다. + </AlertDescription> + </Alert> + )} + + {pqSubmission.status === "APPROVED" && ( + <Alert variant="success"> + <AlertTitle>승인됨</AlertTitle> + <AlertDescription> + {formatDate(pqSubmission.approvedAt)}에 승인되었습니다. + </AlertDescription> + </Alert> + )} + + {pqSubmission.status === "REJECTED" && ( + <Alert variant="destructive"> + <AlertTitle>거부됨</AlertTitle> + <AlertDescription> + {formatDate(pqSubmission.rejectedAt)}에 거부되었습니다. + {pqSubmission.rejectReason && ( + <div className="mt-2"> + <strong>사유:</strong> {pqSubmission.rejectReason} + </div> + )} + </AlertDescription> + </Alert> + )} + + <Separator /> + + {/* PQ 검토 컴포넌트 */} + <Tabs defaultValue="review" className="w-full"> + <TabsList> + <TabsTrigger value="review">PQ 검토</TabsTrigger> + <TabsTrigger value="vendor-info">협력업체 정보</TabsTrigger> + </TabsList> + + <TabsContent value="review" className="mt-4"> + <PQReviewWrapper + pqData={pqData} + vendorId={vendorId} + pqSubmission={pqSubmission} + canReview={canReview} + /> + </TabsContent> + + <TabsContent value="vendor-info" className="mt-4"> + <div className="rounded-md border p-4"> + <h3 className="text-lg font-medium mb-4">협력업체 정보</h3> + <div className="grid grid-cols-2 gap-4"> + <div> + <p className="text-sm font-medium text-muted-foreground">업체명</p> + <p>{pqSubmission.vendorName}</p> + </div> + <div> + <p className="text-sm font-medium text-muted-foreground">업체 코드</p> + <p>{pqSubmission.vendorCode}</p> + </div> + <div> + <p className="text-sm font-medium text-muted-foreground">상태</p> + <p>{pqSubmission.vendorStatus}</p> + </div> + {/* 필요시 추가 정보 표시 */} + </div> + </div> + </TabsContent> + </Tabs> + </Shell> + ) + } catch (error) { + console.error("Error loading PQ:", error) + notFound() + } +} + +// 상태 레이블 함수 +function getStatusLabel(status: string): string { + switch (status) { + case "REQUESTED": + return "요청됨"; + case "IN_PROGRESS": + return "진행 중"; + case "SUBMITTED": + return "제출됨"; + case "APPROVED": + return "승인됨"; + case "REJECTED": + return "거부됨"; + default: + return status; + } +} + +// 상태별 Badge 스타일 +function getStatusVariant(status: string): "default" | "outline" | "secondary" | "destructive" | "success" { + switch (status) { + case "REQUESTED": + return "outline"; + case "IN_PROGRESS": + return "secondary"; + case "SUBMITTED": + return "default"; + case "APPROVED": + return "success"; + case "REJECTED": + return "destructive"; + default: + return "outline"; + } +} + +// 날짜 형식화 함수 +function formatDate(date: Date | null) { + if (!date) return "날짜 없음"; + return new Date(date).toLocaleDateString("ko-KR", { + year: "numeric", + month: "long", + day: "numeric", + hour: "2-digit", + minute: "2-digit" + }); +}
\ No newline at end of file |
